#include <string.h>
#include <netinet/in.h>

#include "cksum.h"
#include "../dll.h"

typedef unsigned short u_short;
typedef unsigned long u_long;

/* Algoritmo que implementa checksum de 16 bits.
 * p_buf = dados a serem analisados
 * Count = tamanho do buf em bytes
 * */
u_short cal_cksum( void *p_buf, int count )
{
    u_long sum = 0;
    u_short *buf = (u_short*) p_buf;
    count /= 2; /* Count deve ser medido em multiplo de 16 bits */

    while(count--)
    {
        sum += *buf++;
        if(sum & 0xFFFF0000)
        {
            /* Vai um */
            sum &= 0xFFFF;
            sum++;
        }
    }   

    return (u_short) ~(sum & 0xFFFF);
}

/* Coloca zero no valor do cheksum do frame */
void fillz_cksum( void *p_buf )
{
    char *buf = (char*) p_buf;
    memset((buf+(HEADER_SIZE - CK_LENGTH)), '\0', CK_LENGTH);
}

/* Insere o cheksum no frame.
 * p_buf = frame, count = tamanho em bytes do frame.
 */
void insert_cksum( void *p_buf, int count )
{
    char *buf = (char*) p_buf;
    u_short cksum;

    fillz_cksum(p_buf);
    cksum = htons(cal_cksum(p_buf, count));

    /* Coloca o valor do checksum no frame */
    memcpy((buf+(HEADER_SIZE - CK_LENGTH)), (char*)(&cksum), CK_LENGTH);    
}

/* Testa se o cheksum da menssagem esta correto. Retorna 1 se sim, 0 se nao.
 * p_buf = frame, count = tamanho em bytes do frame.
 */
int test_cksum( void *p_buf, int count )
{
    u_short old_cksum;
    char *buf = (char*) p_buf;
    memcpy((char*)(&old_cksum), (buf+(HEADER_SIZE - CK_LENGTH)), CK_LENGTH);
    fillz_cksum(p_buf);
    old_cksum = ntohs(old_cksum);

    return (old_cksum == cal_cksum(p_buf, count));
}

